/*
 * main.c
 *
 *  Created on: Jan 14, 2014
 *      Author: jqc
 */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>

#include "config.h"
#include "returnval.h"
#include "fileoper.h"
#include "keyvaloper.h"

#define DEBUG	(DEBUG_SWITCH && 0)

static char fpath[LEN_PATH_MAX] =
{ '\0' };
static char item[LEN_KEY_MAX + LEN_VAL_MAX] =
{ '\0' };
static int opercode = -1;

static int cmdParse(int argc, char **argv)
{
	if (argc < 3) {
		fprintf(stderr, "Usage : %s -o <oper>=\"<key>#<value>\" [-p fpath]\n", argv[0]);
		return OPER_EOPT;
	}

	struct option longopt[] =
	{
	{ "path", required_argument, 0, 'p' },
	{ "operation", required_argument, 0, 'o' },
	{ 0, 0, 0, 0 } };

	int opt = -1;
	char *p = NULL;

	while (EOF != (opt = getopt_long_only(argc, argv, "p:o:", longopt, NULL))) {
		switch (opt) {
		case 'p': {
			strncpy(fpath, optarg, sizeof(fpath));
			break;
		}
		case 'o': {
			if (NULL == (p = strstr(optarg, "=")) || 1 >= strlen(p))
				return OPER_EOPER;

			if (0 == strncmp(optarg, "add", 3)) {
				opercode = CMD_ADD;
			} else if (0 == strncmp(optarg, "del", 3)) {
				opercode = CMD_DEL;
			} else if (0 == strncmp(optarg, "mod", 3)) {
				opercode = CMD_MOD;
			} else if (0 == strncmp(optarg, "qur", 3)) {
				opercode = CMD_QUR;
			} else
				return OPER_EOPER;

			*p = '\0';
			strncpy(item, p + 1, sizeof(item));
			if (DEBUG)
				fprintf(stderr, "item = %s\n", item);

			break;
		}
		default:
			return OPER_EOPT;
		}
	}

	if (-1 == opercode) {
		fprintf(stderr, "[%s] missing -o option!\n", __func__);
		return OPER_EOPT;
	}

	return 0;
}

static int taskAssign(int cmd, NODE *map, char *stritem)
{
	int count = 0;
	int ret = -1;
	CONFIGITEM data;

	if (DEBUG)
		fprintf(stderr, "[%s] stritem=%s\n", __func__, stritem);

	memset(&data, 0, sizeof(CONFIGITEM));
	if (1 > (count = sscanf(stritem, "%[^#]#%s", data.key, data.val))) {
		fprintf(stderr, "[%s] key=%s,value=%s\n", __func__, data.key, data.val);
		fprintf(stderr, "[%s] key or value is invalid %s\n", __func__, strerror(errno));
		return OPER_EOPER;
	}

	switch (cmd) {
	case CMD_ADD:
		ret = confItemAdd(map, &data);
		break;
	case CMD_DEL:
		ret = confItemDel(map, data.key);
		break;
	case CMD_MOD:
		ret = confItemMod(map, &data);
		break;
	case CMD_QUR:
		ret = confItemQur(map, &data);
		fprintf(stdout, "%s\n", data.val);
		break;
	}

	return ret;
}

int main(int argc, char **argv)
{
	int ret = OPER_SUCE;

	// step1 : cmd parse
	if (0 != (ret = cmdParse(argc, argv))) {
		fprintf(stderr, "[%s] command parse error!\n", __func__);
		exit(ret);
	}

	if (0 == strlen(fpath))
		strncpy(fpath, DEF_CONF_PATH, sizeof(fpath));
	if (DEBUG)
		fprintf(stderr, "fpath = %s, opercode=%d\n", fpath, opercode);

	// step2 : load config file to key-value structure
	FILE *fp = NULL;
	if (0 != (ret = lockFile(fpath, &fp))) {
		fprintf(stderr, "[%s] config file lock error!\n", __func__);
		exit(ret);
	}

	NODE *confmap = NULL;
	if (NULL == (confmap = loadConfFile(fp))) {
		free(confmap);
		exit(OPER_EFILE);
	}
	if (DEBUG) {
		NODE *iter = confmap->next;
		while (NULL != iter) {
			if (TLINE_CONF == iter->data.type)
				fprintf(stderr, "[%s] load ... <%s:%s>\n", __func__, iter->data.ctnt.conf.key,
						iter->data.ctnt.conf.val);
			else
				fprintf(stderr, "[%s] load ... content=%s\n", __func__, iter->data.ctnt.notConf);
			iter = iter->next;
		}
	}

	// step3 : do request
	if (0 != (ret = taskAssign(opercode, confmap, item))) {
		free(confmap);
		exit(ret);
	}
	if (DEBUG) {
		NODE *iter = confmap->next;
		while (NULL != iter) {
			if (TLINE_CONF == iter->data.type)
				fprintf(stderr, "[%s] task ... <%s:%s>\n", __func__, iter->data.ctnt.conf.key,
						iter->data.ctnt.conf.val);
			else
				fprintf(stderr, "[%s] task ... content=%s\n", __func__, iter->data.ctnt.notConf);
			iter = iter->next;
		}
	}

	// step4 : write new key-value back to config file
	if (0 != (ret = writeConfFile(fp, confmap))) {
		free(confmap);
		exit(ret);
	}

	free(confmap);
	unlockFile(fp);

	return OPER_SUCE;
}
